

#include "DAP_config.h"
#include "SW_DP_SPI.h"
#include "DAP.h"
#include "port_common.h"
#include "spi_op.h"
#include "spi_switch.h"
#include "dap_utility.h"

#if (DAP_SWD != 0)
//在连接时，调用该函数，初始化spi
void SPI_PORT_SWD_SETUP(void)
{
    DAP_SPI_Deinit();
}
#endif



#if ((DAP_SWD != 0) || (DAP_JTAG != 0))

#include "esp_log.h"
//切换到swd模式，发送一段swj序列
void SPI_SWJ_Sequence(uint32_t count, const uint8_t *data)
{
    // 调用SPI写比特函数，写入指定数量的比特数据
    DAP_SPI_WriteBits(count, data);
}
#endif /* ((DAP_SWD != 0) || (DAP_JTAG != 0))*/

// Generate SWD Sequence
//   info:   sequence information
//   swdo:   pointer to SWDIO generated data
//   swdi:   pointer to SWDIO captured data
//   return: none
#if (DAP_SWD != 0)
// 使用SPI方式生成SWD序列

void SPI_SWD_Sequence(uint32_t info, const uint8_t *swdo, uint8_t *swdi)
{
    // 用于记录时钟周期数
    uint32_t n;
    // 从info中提取时钟周期数
    n = info & SWD_SEQUENCE_CLK;
    // 如果时钟周期数为0，则默认设置为64
    if (n == 0U) {
        n = 64U;
    }
    // n的范围是1 ~ 64

    // 如果info中指示需要读取数据
    if (info & SWD_SEQUENCE_DIN) {
        // 调用SPI读取指定数量的比特数据到swdi指针指向的位置
        DAP_SPI_ReadBits(n, swdi);
    } else {
        // 调用SPI写入指定数量的比特数据，数据从swdo指针指向的位置获取
        DAP_SPI_WriteBits(n, swdo);
    }
}
#endif

#if (DAP_SWD != 0)

uint8_t  SPI_SWD_Transfer(uint32_t request, uint32_t *data)
{
    //// FIXME: 溢出检测
    // SPI传输模式不需要PIN_DELAY等操作
    // 用于存储应答码
    uint8_t ack;
    // uint32_t bit;
    // 用于存储数据值
    uint32_t val;
    // 用于存储接收到的奇偶校验位
    uint8_t parity;
    // 用于存储计算得到的奇偶校验位
    uint8_t computedParity;

    // 用于记录空闲周期数
    uint32_t n;

    // 固定的起始位、停止位和空闲位
    const uint8_t constantBits = 0b10000001U; /* Start Bit  & Stop Bit & Park Bit is fixed. */
    // 存储请求字节
    uint8_t requestByte; /* LSB */

    // 计算请求字节
    requestByte = constantBits | (((uint8_t)(request & 0xFU)) << 1U) | (ParityEvenUint8(request & 0xFU) << 5U);
    /* 对于4位数据，奇偶校验可以等效于高4位全为0的8位数据 */

#if (PRINT_SWD_PROTOCOL == 1)
    // 根据请求字节打印不同的信息
    switch (requestByte) {
        case 0xA5U:
            os_printf("IDCODE\r\n");
            break;
        case 0xA9U:
            os_printf("W CTRL/STAT\r\n");
            break;
        case 0xBDU:
            os_printf("RDBUFF\r\n");
            break;
        case 0x8DU:
            os_printf("R CTRL/STAT\r\n");
            break;
        case 0x81U:
            os_printf("W ABORT\r\n");
            break;
        case 0xB1U:
            os_printf("W SELECT\r\n");
            break;
        case 0xBBU:
            os_printf("W APc\r\n");
            break;
        case 0x9FU:
            os_printf("R APc\r\n");
            break;
        case 0x8BU:
            os_printf("W AP4\r\n");
            break;
        case 0xA3U:
            os_printf("W AP0\r\n");
            break;
        case 0X87U:
            os_printf("R AP0\r\n");
            break;
        case 0xB7U:
            os_printf("R AP8\r\n");
            break;
        default:
            // W AP8
            os_printf("Unknown:%08x\r\n", requestByte);
            break;
    }
#endif

    // 如果请求是读取数据
    if (request & DAP_TRANSFER_RnW) {
        /* Read data */

        // 发送请求头，并获取应答码
        DAP_SPI_Send_Header(requestByte, &ack, 0); // 0 Trn After ACK
        //ESP_LOGI("SWD", "SWD_SPI_Send_Header: %02x" ,ack);
        // 如果应答码为OK
        if (ack == DAP_TRANSFER_OK) {
            // 读取数据和奇偶校验位
            DAP_SPI_Read_Data(&val, &parity);
            // 计算数据的奇偶校验位
            computedParity = ParityEvenUint32(val);

            // 如果计算得到的奇偶校验位和接收到的奇偶校验位不一致
            if ((computedParity ^ parity) & 1U) {
                // 应答码设置为错误
                ack = DAP_TRANSFER_ERROR;
            }
            // 如果data指针不为空
            if (data) {
                *data = val;
            }

            /* Capture Timestamp */
            // 如果请求中包含时间戳标志
            if (request & DAP_TRANSFER_TIMESTAMP) {
                // 获取时间戳并存储到DAP_Data中
                DAP_Data.timestamp = TIMESTAMP_GET();
            }
        }
        // 如果应答码为WAIT或FAULT
        else if ((ack == DAP_TRANSFER_WAIT) || (ack == DAP_TRANSFER_FAULT)) {
#if defined CONFIG_IDF_TARGET_ESP8266 || defined CONFIG_IDF_TARGET_ESP32
            // 生成一个时钟周期
            DAP_SPI_Generate_Cycle(1);
#elif defined CONFIG_IDF_TARGET_ESP32C3 || defined CONFIG_IDF_TARGET_ESP32S3
            // 快速生成一个时钟周期
            DAP_SPI_Fast_Cycle();
#endif

#if (PRINT_SWD_PROTOCOL == 1)
            os_printf("WAIT\r\n");
#endif

            // return DAP_TRANSFER_WAIT;
        } else {
            /* Protocol error */
            // 设置SWDIO/TMS引脚为高电平
            PIN_SWDIO_TMS_SET();

            // 处理SPI协议读取错误
            DAP_SPI_Protocol_Error_Read();

            // 设置SWDIO/TMS引脚为高电平
            PIN_SWDIO_TMS_SET();
#if (PRINT_SWD_PROTOCOL == 1)
            os_printf("Protocol Error: Read\r\n");
#endif
        }

        // 返回应答码
        return ((uint8_t)ack);
    } else {
        /* Write data */
        // 计算数据的奇偶校验位
        parity = ParityEvenUint32(*data);
        // 发送请求头，并获取应答码
        DAP_SPI_Send_Header(requestByte, &ack, 1); // 1 Trn After ACK
        // 如果应答码为OK
        if (ack == DAP_TRANSFER_OK) {
            // 写入数据和奇偶校验位
            DAP_SPI_Write_Data(*data, parity);
            /* Capture Timestamp */
            // 如果请求中包含时间戳标志
            if (request & DAP_TRANSFER_TIMESTAMP) {
                // 获取时间戳并存储到DAP_Data中
                DAP_Data.timestamp = TIMESTAMP_GET();
            }
            /* Idle cycles */
            // 获取空闲周期数
            n = DAP_Data.transfer.idle_cycles;
            // 如果空闲周期数不为0
            if (n) {
                DAP_SPI_Generate_Cycle(n);
            }

            // 设置SWDIO/TMS引脚为高电平
            PIN_SWDIO_TMS_SET();

            // 返回应答码
            return ((uint8_t)ack);
        }
        // 如果应答码为WAIT或FAULT
        else if ((ack == DAP_TRANSFER_WAIT) || (ack == DAP_TRANSFER_FAULT)) {
            /* already turnaround. */

            /* TODO: overrun transfer -> for read */
#if (PRINT_SWD_PROTOCOL == 1)
            os_printf("WAIT\r\n");
#endif
        } else {
            /* Protocol error */
            // 设置SWDIO/TMS引脚为高电平
            PIN_SWDIO_TMS_SET();

            // 处理SPI协议写入错误
            DAP_SPI_Protocol_Error_Write();

            // 设置SWDIO/TMS引脚为高电平
            PIN_SWDIO_TMS_SET();

#if (PRINT_SWD_PROTOCOL == 1)
            os_printf("Protocol Error: Write\r\n");
#endif
        }

        // 返回应答码
        return ((uint8_t)ack);
    }

    // 默认返回错误应答码
    return DAP_TRANSFER_ERROR;
}

#endif /* (DAP_SWD != 0) */
